/**
 * @Author: lll
 * @Email:li.lele@vpclub.cn
 * @Date: create in 2020/7/6
 */
package cn.vpclub.admin.web.home;

import cn.vpclub.admin.annotation.MustToken;
import cn.vpclub.admin.entity.MenuEntity;
import cn.vpclub.admin.entity.UserEntity;
import cn.vpclub.admin.entity.UserMenuEntity;
import cn.vpclub.admin.exception.NoPermissionException;
import cn.vpclub.admin.exception.TokenWrongException;
import cn.vpclub.admin.mapper.MenuMapper;
import cn.vpclub.admin.mapper.UserMapper;
import cn.vpclub.admin.mapper.UserMenuMapper;
import cn.vpclub.admin.param.DeleteByIdParam;
import cn.vpclub.admin.param.LoginParam;
import cn.vpclub.admin.util.BaseResponse;
import cn.vpclub.admin.util.ResponseCodeEnum;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.builder.ExcelWriterBuilder;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.poi.ss.usermodel.Sheet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

@RestController
@RequestMapping(value = "user")
public class UserController {
    Logger log = LoggerFactory.getLogger(UserController.class);
    @Autowired
    UserMapper userMapper;
    @Autowired
    MenuMapper menuMapper;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    UserMenuMapper userMenuMapper;
    @Value("${messageDigest.salt1}")
    String salt1;
    @Value("${messageDigest.salt2}")
    String salt2;
    @Value("${messageDigest.secret}")
    String secret;
    //token  暂定10s到期
    long EXPIRE_TIME = 1000 * 60 * 60;

    /**
     * 注册
     *
     * @param userEntity
     * @return
     */
    @RequestMapping(value = "register", method = RequestMethod.POST)
    @MustToken(required = true, role = "admin")
    public BaseResponse register(@RequestBody @Validated UserEntity userEntity) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        if (!userEntity.getPassword().equals(userEntity.getPasswordAgain())) {
            return BaseResponse.info(ResponseCodeEnum.PasswordNotEqual, null);
        }
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("username", userEntity.getUsername());
        List<UserEntity> list = userMapper.selectList(queryWrapper);
        if (list.size() > 0) {
            return BaseResponse.info(ResponseCodeEnum.UserExit, null);
        }
        String password = this.getMessageDigest(userEntity.getPassword());
        userEntity.setPassword(password);
        userMapper.insert(userEntity);
        return BaseResponse.info(ResponseCodeEnum.SUCCESS, null);
    }

    /**
     * JWT login
     *
     * @param
     * @return
     * @throws UnsupportedEncodingException
     * @throws NoSuchAlgorithmException
     */
    @RequestMapping(value = "login", method = RequestMethod.POST)
    public BaseResponse login(@RequestBody @Validated LoginParam loginParam, HttpServletRequest httpServletRequest) throws UnsupportedEncodingException, NoSuchAlgorithmException {
//        String ip = GetIpUtil.getIpAddress(httpServletRequest);
//        String time = loginParam.getTimeCode();
//        String code = stringRedisTemplate.opsForValue().get(time + ip);
//        if (code == null || !code.equals(loginParam.getCode())) {
//            return BaseResponse.info(ResponseCodeEnum.CodeWrong, null);
//        }
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("username", loginParam.getUsername());
        queryWrapper.eq("password", this.getMessageDigest(loginParam.getPassword()));
        List<UserEntity> list = userMapper.selectList(queryWrapper);
        if (list.size() == 0) {
            return BaseResponse.info(ResponseCodeEnum.UserNotExit, null);
        }
        Map<String, Object> map = new HashMap<>();
        //生成token
        String token = this.getToken(list.get(0).getId(), loginParam.getUsername(), loginParam.getPassword());
        log.info("获取用户 {} 登陆成功之后生成的的token {} ", loginParam.getUsername(), token);
        map.put("token", token);
        map.put("createdTime", System.currentTimeMillis());
        map.put("expireTime", this.EXPIRE_TIME / 1000);
        map.put("username", list.get(0).getUsername());
        map.put("role", list.get(0).getRole());
//        if (list2.size() == 0) {
//            map.put("menu", new ArrayList<>());
//        } else {
//            map.put("menu", this.getMenu(list2));
//        }
        return BaseResponse.info(ResponseCodeEnum.SUCCESS, map);
    }

    /**
     * 根据id查询用户信息
     *
     * @param httpServletRequest
     * @return
     */
    @RequestMapping(value = "selectUserInfo")
    public BaseResponse selectUserInfo(HttpServletRequest httpServletRequest) {
        String id = (String) httpServletRequest.getAttribute("userId");
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("id", id);
        List<UserEntity> list = userMapper.selectList(queryWrapper);
        if (list.size() == 0) {
            return BaseResponse.info(ResponseCodeEnum.NOUSER, null);
        }
        return BaseResponse.info(ResponseCodeEnum.SUCCESS, list);
    }

    /**
     * hash sha-256加盐加密密码
     *
     * @param password
     * @return
     * @throws NoSuchAlgorithmException
     * @throws UnsupportedEncodingException
     */
    public String getMessageDigest(String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
        messageDigest.update((password + salt1 + salt2).getBytes("UTF-8"));
        byte[] result = messageDigest.digest();
        String finalPassword = new BigInteger(1, result).toString(16);
        log.info("sha-256加密密码：{}", finalPassword);
        return finalPassword;
    }

    /**
     * 生成token
     *
     * @param id
     * @param username
     * @param password
     * @return
     */
    public String getToken(String id, String username, String password) {
        Algorithm algorithm = Algorithm.HMAC256(secret);
        String token = JWT.create()
                .withAudience(id.toString())
                .withIssuer("auth0")
                .withIssuedAt(new Date())
                .withExpiresAt(new Date(System.currentTimeMillis() + this.EXPIRE_TIME))
//                .withSubject("sub")
//                .withIssuedAt(new Date()).withClaim("data", "hello")
//                .withJWTId(UUID.randomUUID().toString())
                .sign(algorithm);
        return token;
    }

    /*
     * 根据token查询菜单
     * */
    @RequestMapping(value = "getMenuByToken", method = RequestMethod.POST)
    @MustToken(required = true, role = "admin")
    public BaseResponse getMenuByToken(HttpServletRequest httpServletRequest) {
        //登陆用户id
        String id = (String) httpServletRequest.getAttribute("userId");
        //查询用户菜单表
        QueryWrapper userMenuQueryWrapper = new QueryWrapper();
        userMenuQueryWrapper.eq("user_id", id);
        List<UserMenuEntity> userMenuList = userMenuMapper.selectList(userMenuQueryWrapper);
        List list2 = new ArrayList();
        for (UserMenuEntity userMenuEntity : userMenuList) {
            list2.add(userMenuEntity.getMenuId());
        }
        QueryWrapper queryWrapper = new QueryWrapper();
        //查询父级菜单
        queryWrapper.eq("level", 0);
        queryWrapper.in("id", list2);
        queryWrapper.select("id", "menu_name", "menu_url", "menu_icon", "menu_order");
        queryWrapper.orderByAsc("menu_order");
        List<MenuEntity> list = menuMapper.selectList(queryWrapper);
        List listParent = new ArrayList();
        for (Integer i = 0; i < list.size(); i++) {
            Map<String, Object> map = new HashMap();
            map.put("menuIcon", list.get(i).getMenuIcon());
            map.put("menuName", list.get(i).getMenuName());
            map.put("menuUrl", list.get(i).getMenuUrl());
            map.put("id", list.get(i).getId());
            QueryWrapper queryWrapper1 = new QueryWrapper();
            queryWrapper1.eq("level", 1);
            queryWrapper1.eq("parent_menu_name", list.get(i).getMenuName());
            queryWrapper.orderByAsc("menu_order");
            queryWrapper.select("id", "menu_name", "menu_url", "menu_icon", "menu_order");
            List<MenuEntity> list1 = menuMapper.selectList(queryWrapper1);
            map.put("subs", list1);
            listParent.add(map);
        }
        return BaseResponse.info(ResponseCodeEnum.SUCCESS, listParent);
    }

    /**
     * 查询user列表
     */
    @RequestMapping(value = "getUserInfo", method = RequestMethod.POST)
    @MustToken(required = true, role = "admin")
    public BaseResponse getUserInfo() {
        QueryWrapper queryWrapper = new QueryWrapper();
        List list = new ArrayList();
        list.add("admin");
        queryWrapper.notIn("role", list);
        List<UserEntity> userInfo = userMapper.selectList(queryWrapper);
        return BaseResponse.info(ResponseCodeEnum.SUCCESS, userInfo);
    }

    //删除用户信息
    @RequestMapping(value = "deleteUserInfo", method = RequestMethod.POST)
    @MustToken(required = true, role = "admin")
    public BaseResponse deleteUserInfo(@RequestBody @Validated DeleteByIdParam deleteByIdParam) {
        String id = deleteByIdParam.getId();
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("id", id);
        userMapper.delete(queryWrapper);
        return BaseResponse.info(ResponseCodeEnum.SUCCESS, null);
    }

    //导出用户信息(浏览器自动解析的导入导出吧，a标签，权限验证+url)
    @RequestMapping(value = "exportUserInfo", method = RequestMethod.GET)
    public BaseResponse exportUserInfo(@RequestParam("token") String token, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException {
        String id = JWT.decode(token).getAudience().get(0);
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("id", id);
        List<UserEntity> userInfo = userMapper.selectList(queryWrapper);
        if (userInfo.size() == 0) {
            throw new TokenWrongException();
        }
        if (!userInfo.get(0).getRole().equals("admin")) {
            throw new NoPermissionException("无权限！");
        }
        OutputStream outputStream = httpServletResponse.getOutputStream();
        List list = userMapper.selectList(null);
        //导出文件名，中文编码
        String fileName = new String((URLEncoder.encode("用户信息-", "UTF-8") + new SimpleDateFormat("yyyy-MM-dd:HH-mm").format(new Date())).getBytes(), "UTF-8");
        httpServletResponse.setCharacterEncoding("utf-8");
        httpServletResponse.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        EasyExcel.write(outputStream, UserEntity.class).sheet("用户表").doWrite(list);
        return BaseResponse.info(ResponseCodeEnum.SUCCESS, null);
    }
}
